package com.longcai.utils.fuyoupay;

import org.apache.commons.codec.binary.Base64;

import javax.crypto.Cipher;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

public class FuiouRsaCipher {

    private static final String RSA_CIPHER_CHARSET = "UTF-8";

    static {
        try {
            java.security.Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * @param base64Rsa
     * @param inputStr
     * @return
     */
    public static String sign2Base64(String base64PriRsa, String inputStr) {
        try {
            PrivateKey privateKey = genPrivateKey(base64PriRsa);
            Signature signature = Signature.getInstance("SHA1withRSA", "BC");
            signature.initSign(privateKey);
            signature.update(inputStr.getBytes(RSA_CIPHER_CHARSET));
            return Base64.encodeBase64String(signature.sign());
        } catch (Exception e) {
            e.printStackTrace();
            throw new IllegalArgumentException("rsa签名异常");
        }
    }

    /**
     * @return
     */
    public static boolean verifySign(String base64PubRsa, String src, String base64SignValue) {
        try {
            PublicKey publicKey = genPublicKey(base64PubRsa);
            Signature signature = Signature.getInstance("SHA1withRSA", "BC");
            signature.initVerify(publicKey);
            signature.update(src.getBytes(RSA_CIPHER_CHARSET));
            return signature.verify(Base64.decodeBase64(base64SignValue));
        } catch (Exception e) {
            e.printStackTrace();
            throw new IllegalArgumentException("rsa验证签名异常");
        }
    }

    private static PrivateKey genPrivateKey(String base64Rsa) {
        try {
            KeyFactory kf = KeyFactory.getInstance("RSA", "BC");
            PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(base64Rsa));
            return kf.generatePrivate(keySpec);
        } catch (Exception e) {
            e.printStackTrace();
            throw new IllegalArgumentException("初始化秘钥异常");
        }
    }

    private static PublicKey genPublicKey(String base64Rsa) {
        try {
            KeyFactory kf = KeyFactory.getInstance("RSA", "BC");
            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(Base64.decodeBase64(base64Rsa));
            return kf.generatePublic(keySpec);
        } catch (Exception e) {
            e.printStackTrace();
            throw new IllegalArgumentException("初始化秘钥失败");
        }
    }

    public static String encryptByRsaPub(String src, String base64PubRsa) {
        try {
            PublicKey publicKey = genPublicKey(base64PubRsa);
            byte[] encryptBytes = encryptByPublicKey(src.getBytes(RSA_CIPHER_CHARSET), publicKey);
            return Base64.encodeBase64String(encryptBytes);
        } catch (Exception e) {
            e.printStackTrace();
            throw new IllegalArgumentException("rsa加密失败");
        }
    }

    public static String decryptByRsaPri(String base64Src, String base64PriRsa) {
        try {
            PrivateKey privateKey = genPrivateKey(base64PriRsa);
            return new String(decryptPrivateKey(Base64.decodeBase64(base64Src), privateKey), RSA_CIPHER_CHARSET);
        } catch (Exception e) {
            e.printStackTrace();
            throw new IllegalArgumentException("rsa解密失败");
        }
    }

    /**
     * 公钥加密
     */
    private static byte[] encryptByPublicKey(byte[] srcData, PublicKey publicKey) {
        try {
            Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
            cipher.init(Cipher.ENCRYPT_MODE, publicKey);
            // 分段加密
            int blockSize = cipher.getOutputSize(srcData.length) - 11;
            byte[] encryptedData = null;
            for (int i = 0; i < srcData.length; i += blockSize) {
                // 注意要使用2的倍数，否则会出现加密后的内容再解密时为乱码
                byte[] doFinal = cipher.doFinal(subarray(srcData, i, i + blockSize));
                encryptedData = addAll(encryptedData, doFinal);
            }
            return encryptedData;

        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 私钥算法
     *
     * @param srcData    源字节
     * @param privateKey 私钥
     * @param mode       加密 OR 解密
     * @return
     */
    private static byte[] decryptPrivateKey(byte[] srcData, PrivateKey privateKey) {
        try {
            Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
            cipher.init(Cipher.DECRYPT_MODE, privateKey);
            // 分段加密
            int blockSize = cipher.getOutputSize(srcData.length);
            byte[] decryptData = null;

            for (int i = 0; i < srcData.length; i += blockSize) {
                byte[] doFinal = cipher.doFinal(subarray(srcData, i, i + blockSize));

                decryptData = addAll(decryptData, doFinal);
            }
            return decryptData;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    private static byte[] subarray(byte[] array, int startIndexInclusive, int endIndexExclusive) {
        if (array == null) {
            return null;
        }
        if (startIndexInclusive < 0) {
            startIndexInclusive = 0;
        }
        if (endIndexExclusive > array.length) {
            endIndexExclusive = array.length;
        }
        int newSize = endIndexExclusive - startIndexInclusive;

        if (newSize <= 0) {
            return new byte[0];
        }

        byte[] subarray = new byte[newSize];

        System.arraycopy(array, startIndexInclusive, subarray, 0, newSize);

        return subarray;
    }

    private static byte[] addAll(byte[] array1, byte[] array2) {
        if (array1 == null) {
            return clone(array2);
        } else if (array2 == null) {
            return clone(array1);
        }
        byte[] joinedArray = new byte[array1.length + array2.length];
        System.arraycopy(array1, 0, joinedArray, 0, array1.length);
        System.arraycopy(array2, 0, joinedArray, array1.length, array2.length);
        return joinedArray;
    }

    public static byte[] clone(byte[] array) {
        if (array == null) {
            return null;
        }
        return (byte[]) array.clone();
    }

    public static void main(String[] args) {
        String rsaPubBase64 = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAI0wTj1wXcZCBSNrhx/qLvDb52p5mx9aH+lNPWUz9EPZRUA+gOhz9GJKt9vFWdg8UumB+rZlu16Ob1r+ZLGEtK+pU6mzhsXNUOALnIBUxaMTOmjV/HpWxaFk2IlfJ4JHrE7WZMP7MpvZpQWckNhUL+2VbbPHdJuwT9t5vTqKNdKfAgMBAAECgYAJolo0Zw5/ENI48IVv8BLz7I2F/nZPVV8IFHU0Cq+IUbMgByPUuNTcQCz7miPfVX5y4KOy/o4ijaWbl/BXDK8nk2/NaryLalMfbRk1pQHl7qq84nCLT2IPs2pTpSTDWRSccEoFBnbigXCd/4fXjZHRqMK2spOACfixs7T+LQStwQJBAMoR5sNjSquYnf1yHfhngnWQQQCIEcMs4rip813wjlVtfF+VHUttZ6iAcNaASCXiwvTsNQaHJ91rM8Zn8ze/G8UCQQCy3ssJNtI1fumoAQK/xXVOZiyTMpdK7m+W/+2Ba5cajFwHnW3fLKW/Y8/Xl0GPT4AeMddLkFYzex0k+2kYmOcTAkEAieKNROaMHWuW40rriIWZT/+PW31+IWCPlNLjbkan2UNMiyyFQOL2yNRcKwJ+ONvzjI1h4YJ4gW6Vdd2Y6YFOwQJANakrBiehJpVdaZ5sAbYuPAfhBYPe6YbgiU9cJEBvw3IqRcqP5K0TSHicKNRiwaibCfPv3+Z8RdOAadDWtZ9hawJATypfM2sODKzY/aZGejU7TESpCAOC8o3QD8lBCVRpHOgj2UGp98oAQ251tfW+CDXZ7umO2ODQL7ksFuGRIHcUsg==";
        /**
         * @Fields PRI_SIGN_KEY : 私钥
         */
        String rsaPriBase64 = "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAMU/yu6SBhYo2YRrU5J5Ets7UOEXgdqfkeAPDvV+XPWwQFKE5L+TiFgZC9la4iLJBMU0ewFb7sdzH9QVD2JFKdI0kBeYi/H1l3NipliPgIMO5OhC39B/7tc16W3tt0ks49SzjPwr+CVNBfwEqcN8Te1gXHO+wUqPQsfMEBGWyq+rAgMBAAECgYEAkPCgUI/ycwQPWdN3tJDM/1VlyBD69Uf97BOEnXX+HvclPL20TOW+8WVuJIg41PC7VaGLpWMFYX/B6piTFlXWNPrfwM9UWPCrhojsuwUPetCweGP0QvzMxKu+O5iFtciNZRPRNnhzvscLCCIc3AIQhW2os7tHxvfr5YRmkAjR4hkCQQDl6qHPIr/c6Ejw//tARITSqru6pV3dFzZSLhxLH2YiitiswsP60AaVNCC9LedVv2D5DBFFCqKelKv8tkQBXL+lAkEA26BqvWKqkPiSlhQg4QLIl1Xxq/bFU0ejZV9IOM3qoVSEB08w59fmscVuqGIHdcRVI1abiXIst9e9pEfT2WORDwJAGMvBP7Gjt5NlqngxBLFfEclQDcUf5mRGe351lrSAM2F+FMO8lyQwUY8ZqM12kYzeTH28rxGCkE/AbLTLiMoT8QJAamdKr1xI9JlpM0qnLzxRAHjD8CNLMHDJqchCzjp9DRJMMNpeAETqYIAdf3iW0qh+8vL3wdxN6/eayid+bJi/YwJBALYNG4klSl9ApSdqaxZTKDjwNIbfva2vk1bNPTZk24y1qXU42S/9Z3IrAKnggYFaBumCIOiiLhXIjaGlnNDunXw=";

//		String rsaPubBase64 = "MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKwHTjMXJhagjboA16YWMbQxUBHFP7bNdp0FZiwoVXBISwVN55nsMTjXZKAcc4r46Y5ehyczQJjsFA3xtiZT7osCAwEAAQ==";
//		String rsaPriBase64 = "MIIBUwIBADANBgkqhkiG9w0BAQEFAASCAT0wggE5AgEAAkEArAdOMxcmFqCNugDXphYxtDFQEcU/ts12nQVmLChVcEhLBU3nmewxONdkoBxzivjpjl6HJzNAmOwUDfG2JlPuiwIDAQABAkBWV/xaDF5jsQYxu8aBaFZeOPoVUUmfeRT1zwXvV/c6OVwWShmtcV5rA3pURp9wAKmBJqOrXMqgIq4LFlOTKp1RAiEA2QQXug5FuUq5PKWg3S20p7JIq4UQeRIzYfTXYdgN1J8CIQDK7mBYGquXKprSkwuBRMgpAO1N6aN43kvg24ow3iwSlQIgbYeQRhpv/F4HceGSeC9aT40++jqVntWd02HU1xBJorcCIAOd2/m1//jhuYCnPj0/jJGugoww7cjprVCEmSHl08NBAiAPPmtd7s+9aeg9v1bc6kLeSW96DPJJ9lpkP2iK7nREkg==";
//		String inputStr = "test验证rsa加密";
//		String sign = sign2Base64(rsaPriBase64, inputStr);
//		System.out.println("加密结果:" + sign);
//		boolean verifySign = verifySign(rsaPubBase64, inputStr, sign);
//		System.out.println("验签结果：" + verifySign);


//		genPrivateKey(rsaPriBase64);
//		System.out.println("==============================");
//		genPublicKey(rsaPubBase64);


//		String src = UUID.randomUUID().toString();
        //String src = "楼晶|J2900184379402|0002900F1766674|710501425540450248710101|兴业银行股份有限公司上海青浦支行|上海美问信息科技有限公司|216400100100058711|310108197411014820|2900|310105324509997|2025-01-26|上海美问信息科技有限公司|0.44";
        String src = "0002900F1001919|19920000370|04";
        System.out.println(src);
        String encode = "PKTAAHzbHiUp9CgAysHy/wRK5nWFEuMjonQZS7yU555nn3P82DEvTmgiP8X7vSsEGbytDcWeDbtforz5nqEnCM13vnWr5EYFMyiGFJQ9nTIdb/FfPh6Ut38UxLRfglS14Lgc52Bt8kLjJAZKfS0BTIa/t3Zlqm6083HTVVAY+tkD6UkVvO1VehVCGP07RUPikpwn0fiNEytbjdmkwKme+6yTHaxKKQeCMokIqd0mdYCuSE7ByvqrRrf9+Kku6ksMgdAYHGY0aM4jZiH0eg33gNp7JLYf+xz/H+ax6+S454rStNSHR7TJlnj5ummMW0Rhx71zwEtxg/9IjwqcVHLomQ==";
        System.out.println(encode);
        System.out.println("11111" + verifySign(rsaPubBase64, src, encode));
//		String encryptByRsaPub = encryptByRsaPub(src, rsaPubBase64);
//		System.out.println(encryptByRsaPub);
//		String decryptByRsaPri = decryptByRsaPri(encryptByRsaPub, rsaPriBase64);
//		System.out.println(decryptByRsaPri);

    }

}
